/* i2c - Simple example

   Simple I2C example that shows how to initialize I2C
   as well as reading and writing from and to registers for a sensor connected over I2C.

   The sensor used in this example is a MPU9250 inertial measurement unit.

   For other examples please check:
   https://github.com/espressif/esp-idf/tree/master/examples

   See README.md file to get detailed usage of this example.

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "esp_log.h"
#include "driver/i2c.h"
#include "capacitive_hynitron_cst816t_update.h"

static const char *TAG = "i2c-simple-example";

#define I2C_MASTER_SCL_IO           22      /*!< GPIO number used for I2C master clock */
#define I2C_MASTER_SDA_IO            21     /*!< GPIO number used for I2C master data  */
#define I2C_MASTER_NUM              0                          /*!< I2C master i2c port number, the number of i2c peripheral interfaces available will depend on the chip */
#define I2C_MASTER_FREQ_HZ          100000                     /*!< I2C master clock frequency */
#define I2C_MASTER_TX_BUF_DISABLE   0                          /*!< I2C master doesn't need buffer */
#define I2C_MASTER_RX_BUF_DISABLE   0                          /*!< I2C master doesn't need buffer */
#define I2C_MASTER_TIMEOUT_MS       1000

#define MPU9250_SENSOR_ADDR                 0x6a       /*!< Slave address of the MPU9250 sensor */
#define MPU9250_WHO_AM_I_REG_ADDR           0x75        /*!< Register addresses of the "who am I" register */

#define MPU9250_PWR_MGMT_1_REG_ADDR         0x6B        /*!< Register addresses of the power managment register */
#define MPU9250_RESET_BIT                   7
#define TP_RST                      17  
#define TP_INT                      16
#define TP_ADDR                     0x15
#define GPIO_INPUT_IO_0             TP_INT
#define GPIO_INPUT_PIN_SEL          (1ULL<<GPIO_INPUT_IO_0) 
#define ESP_INTR_FLAG_DEFAULT 0
static QueueHandle_t gpio_evt_queue = NULL;
void cst816_read_position(void);
static void IRAM_ATTR gpio_isr_handler(void* arg)
{
    uint32_t gpio_num = (uint32_t) arg;
    xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
    //printf("hello\n");
}

static void gpio_task_example(void* arg)
{
    uint32_t io_num;
    for(;;) {
        if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
            cst816_read_position();
        }
    }
}

/**
 * @brief Read a sequence of bytes from a MPU9250 sensor registers
 */
static esp_err_t cts816tRegisterRead(uint16_t reg_addr, uint8_t *data, size_t write_data_len,size_t len)
{
    uint8_t write_buf[2]; 
    if(write_data_len == 2)
    {
        write_buf[0] = (reg_addr >> 8) &0xff, 
        write_buf[1] = (reg_addr) &0xff;
    }else if(write_data_len == 1)
    {
         write_buf[0] = (reg_addr) &0xff;
    }else{
        return ESP_FAIL;
    }
    return i2c_master_write_read_device(I2C_MASTER_NUM, MPU9250_SENSOR_ADDR, write_buf, write_data_len, data, len, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
}

static esp_err_t cts816tReadBytes(uint16_t reg_addr, uint8_t *data, size_t write_data_len,size_t len)
{
    uint8_t write_buf[2]; 
    if(write_data_len == 2)
    {
        write_buf[0] = (reg_addr >> 8) &0xff, 
        write_buf[1] = (reg_addr) &0xff;
    }else if(write_data_len == 1)
    {
         write_buf[0] = (reg_addr) &0xff;
    }else{
        return ESP_FAIL;
    }
    return i2c_master_write_read_device(I2C_MASTER_NUM, TP_ADDR, write_buf, write_data_len, data, len, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
}

/**
 * @brief Write a byte to a MPU9250 sensor register
 */
static esp_err_t cts816tWriteByte(uint16_t reg_addr, uint8_t data)
{
    int ret;
    uint8_t write_buf[3] = {(reg_addr >> 8) &0xff, (reg_addr) &0xff,data};

    ret = i2c_master_write_to_device(I2C_MASTER_NUM, MPU9250_SENSOR_ADDR, write_buf, sizeof(write_buf), I2C_MASTER_TIMEOUT_MS*3 / portTICK_PERIOD_MS);

    return ret;
}


void test_read_addr()
{
    uint8_t data = 0;
    uint8_t reg_addr = 0xa7;
    esp_err_t ret = 0;
    for(int i = 0; i <=127; i++)
    {
        ret = i2c_master_write_read_device(I2C_MASTER_NUM,i,&reg_addr,1,&data,1, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
        if(ret == ESP_OK )
        {
                ESP_LOGI(TAG, "sendor_id  %x",i);
              vTaskDelay(1 / portTICK_PERIOD_MS);
        }
    }
}

/**
 * @brief i2c master initialization
 */
static esp_err_t i2c_master_init(void)
{
    int i2c_master_port = I2C_MASTER_NUM;

    i2c_config_t conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = I2C_MASTER_SDA_IO,
        .scl_io_num = I2C_MASTER_SCL_IO,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = I2C_MASTER_FREQ_HZ,
    };

    i2c_param_config(i2c_master_port, &conf);

    return i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
}


void cts816tInit()
{
    gpio_reset_pin(TP_RST);
    /* Set the GPIO as a push/pull output */
    gpio_set_direction(TP_RST, GPIO_MODE_OUTPUT);
    gpio_set_level(TP_RST,0);
    vTaskDelay(10 / portTICK_PERIOD_MS);
    gpio_set_level(TP_RST,1);
    vTaskDelay(10 / portTICK_PERIOD_MS);

    gpio_config_t io_conf = {};
    io_conf.intr_type = GPIO_INTR_POSEDGE;
    io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
    io_conf.mode = GPIO_MODE_INPUT;
    io_conf.pull_up_en = 0;
    gpio_config(&io_conf);
    gpio_set_intr_type(GPIO_INPUT_IO_0, GPIO_INTR_ANYEDGE);

    gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));
    xTaskCreate(gpio_task_example, "gpio_task_example", 2048, NULL, 10, NULL);
    gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);

    gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0);

}

int cts816EnterBootMode(void)
{
    esp_err_t ret = 0;
    uint8_t sendor_id = 0;

    ret = cts816tWriteByte(0xA001,0xab);
    ESP_LOGI(TAG,"tp write ret  %d",ret);
    cts816tRegisterRead(0xA003,&sendor_id,2,1);
    //ESP_LOGI(TAG,"sendor_id %x",sendor_id);
    if(sendor_id == 0xc1)
    {
        ESP_LOGI(TAG,"sendor id match success\n");
        return 0;
    }
    
    return  -1;
}

uint16_t cst816_read_checksum()
{
    union{
        uint32_t sum;
        uint8_t buf[4];
    }checksum;
    uint8_t cmd[3];

    cmd[0] = 0;
    cts816tWriteByte(0xa003,cmd[0]);
    vTaskDelay(500 / portTICK_PERIOD_MS);
    checksum.sum = 0;

    cts816tRegisterRead(0xa008,checksum.buf,2,2);
                ESP_LOGI(TAG, "checksum  %ld",checksum.sum);
    return checksum.sum;
}

void ctp_hynitron_update(void)
{
    uint8_t lvaue;

    if(cts816EnterBootMode() == 0)
    {
        if(sizeof(app_bin) > 10)
        {
            uint16_t start_addr = app_bin[1];
            uint16_t length = app_bin[3];
            uint16_t checksum = app_bin[5];
            start_addr <<= 8;
            start_addr |= app_bin[0];
            length <<= 8;
            length |= app_bin[2];
            checksum <<= 8;
            checksum |= app_bin[4];
            ESP_LOGI(TAG,"checksum  %d",checksum);
            if(cst816_read_checksum() != checksum)
            {
                ESP_LOGI(TAG, "cst816 check sum failed\n"); 
            }
        }
    }
}

void CaptureDaaHandle(uint8_t *tp_temp)
{
    uint16_t pdwSampleX,pdwSampleY; 
    uint8_t finger_num = tp_temp[2];  //手指个数
    pdwSampleX = (uint16_t)((tp_temp[3] & 0x0F)<<8)+   (uint16_t)tp_temp[4];
    pdwSampleY = (uint16_t)((tp_temp[5] & 0x0F)<<8) +  (uint16_t)tp_temp[6];
    ESP_LOGI(TAG, "x = %d, y  %d,mode = %d,finger_num = %d\n",pdwSampleX,pdwSampleY,tp_temp[1],finger_num); 
    // if(tp_temp[1] == 0x00)      //报点模式
    // {
    //     ESP_LOGI(TAG, "tp_temp = 0\n"); 
    // }else if(tp_temp[1] == 0x05)
    // {
    //      ESP_LOGI(TAG, "tp_temp = 5\n"); 
    // }else if(tp_temp[1] == 0x0c)
    // {
    //      ESP_LOGI(TAG, "tp_temp = c\n"); 
    // }

}

void cst816_read_position()
{
    uint8_t data[10];
    cts816tReadBytes(0x00,data,1,7);
    CaptureDaaHandle(&data[0]);
}

void app_main(void)
{

    ESP_ERROR_CHECK(i2c_master_init());
    ESP_LOGI(TAG, "I2C initialized successfully");
    cts816tInit();
    //test_read_addr();
    //ctp_hynitron_update();
     ESP_LOGI(TAG, "I2C app main");
      vTaskDelay(100 / portTICK_PERIOD_MS);
     //test_read_addr();
    while (1)
    {
           vTaskDelay(100 / portTICK_PERIOD_MS);
    }
}
